#!/usr/bin/env python2
# coding: utf-8


import unittest
import threading
import time

from zstack import Client
from zstack.controller import vm
from zstack.controller import network
from zstack.controller import system

ADMIN_USERNAME = 'admin'
ADMIN_PASSWORD = 'password'
ZSTACK_API_URL = 'http://192.168.1.115:8080/zstack/api'
ZSTACK_NET_SERVICES = None
CLUSTER_UUID = None
ZONE_UUID = None
VROUTER_IMAGE_UUID = None  # 云路由镜像
PUBLIC_NETWORK = None  # 绑定的EIP网络（公共网络）
HOSTS_NAME = ['test-1', 'test-2', 'test-3', 'test-4']  # 物理机名称
IMAGE_UUID = 'd08a69706d81457fadddbb4fa6ec175e'  # 测试镜像
NIC = 'enp3s0'  # 物理机网卡名

NETWORK_COUNT = 2  # 测试创建网络数目
VM_COUNT = 1  # 测试每个网络下创建虚拟机数目


class TestVM(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.client = Client(ADMIN_USERNAME, ADMIN_PASSWORD, ZSTACK_API_URL)
        cls.client.login()
        config = system.environment_variables_init(cls.client)
        global ZSTACK_NET_SERVICES, CLUSTER_UUID, ZONE_UUID, PUBLIC_NETWORK, VROUTER_IMAGE_UUID, IMAGE_UUID
        ZSTACK_NET_SERVICES = config.get('services') if not ZSTACK_NET_SERVICES else ZSTACK_NET_SERVICES
        CLUSTER_UUID = config.get('cluster_uuid') if not CLUSTER_UUID else CLUSTER_UUID
        ZONE_UUID = config.get('zone_uuid') if not ZONE_UUID else ZONE_UUID
        PUBLIC_NETWORK = config.get('no_vlan_l3_network_uuid') if not PUBLIC_NETWORK else PUBLIC_NETWORK
        VROUTER_IMAGE_UUID = config.get('vrouter_image_uuid') if not VROUTER_IMAGE_UUID else VROUTER_IMAGE_UUID
        IMAGE_UUID = VROUTER_IMAGE_UUID if not IMAGE_UUID else IMAGE_UUID

    # 此测试接口包括：创建计算规格、使能计算规格、不使能计算规格、删除计算规格
    def test_create_enable_disable_delete_instance(self):
        # 创建计算规格
        instance = vm.create_instance_offering(self.client, 'py_instance01', 1, 256)
        self.assertEqual(instance['name'], 'py_instance01')
        self.assertEqual(instance['cpuNum'], 1)
        self.assertEqual(instance['memorySize'], 268435456)

        # 是否在计算规格列表中
        instances = vm.query_instance_offering(self.client)
        self.assertIn(instance['uuid'], [ins.get('uuid') for ins in instances])

        # 根据uuid查询，是否存在
        instance1 = vm.query_instance_offering_by_uuid(self.client, instance['uuid'])
        self.assertIsNotNone(instance1)

        # 不使能计算规格（创建后默认是使能的）
        instance2 = vm.disable_instance_offering_state(self.client, instance['uuid'])
        self.assertEqual(instance2['state'], 'Disabled')

        # 使能计算规格
        instance3 = vm.enable_instance_offering_state(self.client, instance2['uuid'])
        self.assertEqual(instance3['state'], 'Enabled')

        # 删除计算规格
        vm.delete_instance_offering(self.client, instance3['uuid'])
        instance4 = vm.query_instance_offering_by_uuid(self.client, instance3['uuid'])
        self.assertEqual(instance4, [])

    def test_create_update_delete_query_VM(self):
        """新增/绑定浮动IP/删除/查询虚拟机"""
        time_start = time.time()
        net_mutex = threading.Lock()
        vms_uuid = []
        jobs = []
        l3_networks_uuid = []
        # 创建计算规格
        instance_offering_uuid = vm.create_instance_offering(self.client, 'C1-M1G', 1, 1024).get('uuid')

        # 在公共网络（PUBLIC_NETWORK）下创建一个C1-M1G云路由规格
        vrouter_instance_offering_uuid = network.create_virtual_router_template(
            self.client, 'test-vrouter-instance', PUBLIC_NETWORK, VROUTER_IMAGE_UUID, ZONE_UUID).get('uuid')

        # 逐个建立网络和虚拟机
        for i in range(200, 200 + NETWORK_COUNT):
            print(i, time.time() - time_start)
            l3_network_uuid = network.create_network(
                self.client, net_mutex, u'test vrouter%d' % i, '200.' + '.'.join([str(i)] * 2) + '.0/24', NIC,
                'vrouter', resource_uuid=vrouter_instance_offering_uuid,
                # 'Flat',
                services=ZSTACK_NET_SERVICES,
                cluster_uuid=CLUSTER_UUID,
                zone_uuid=ZONE_UUID
            )
            l3_networks_uuid.append(l3_network_uuid)
            print('network%d ok, vm starting' % i, time.time() - time_start)
            for _ in range(VM_COUNT):
                print('vm starting:', time.time() - time_start, jobs)
                jobs.append(vm.create_vm_instance(
                    self.client, 'testvm%d' % _, l3_network_uuid,
                    IMAGE_UUID, instance_offering_uuid, async=True).get('job').get('uuid'))

        for i, job in enumerate(jobs):
            create_vm = self.client.get_api_result(self.client.wait_mission_complete(job))
            print('vm [%s]' % create_vm.get('uuid'), i + 1, job, time.time() - time_start)
            vms_uuid.append(create_vm.get('uuid'))

        print('end  ', time.time() - time_start)

        # 绑定浮动IP，查询vm, 销毁vm
        for vid in vms_uuid:
            # 绑定EIP
            eip = network.get_eip4vm(self.client, PUBLIC_NETWORK, vid)
            eip_ip = eip.get('ip')
            self.assertIn(eip_ip, vm.query_eip_by_vm_instance_uuid(self.client, vid).get('ips'))

            # 查询vm
            self.assertIn(vid, [v.get('uuid') for v in vm.query_vm_instance(self.client)])
            self.assertIn(vid, [v.get('uuid') for v in vm.query_vm_instance_by_username(self.client, ADMIN_USERNAME)])
            self.assertIn(vid, [v.get('uuid') for v in vm.query_vm_instance_by_hosts_name(self.client, HOSTS_NAME)])

            # 销毁EIP
            network.delete_eip_by_uuid(self.client, eip.get('uuid'))
            self.assertNotIn(eip_ip, vm.query_eip_by_vm_instance_uuid(self.client, vid).get('ips'))

            # 销毁vm
            vm.destroy_vm_instance(self.client, vid)
            self.assertNotIn(vid, [v.get('uuid') for v in vm.query_vm_instance(self.client)])

        # 销毁网络
        for uid in l3_networks_uuid:
            network.destroy_l3_network(self.client, uid)
            self.assertNotIn(uid, [net.get('uuid') for net in network.query_l3_network(self.client, details=False)])

        # 销毁计算规格
        vm.delete_instance_offering(self.client, instance_offering_uuid)
        self.assertEqual(vm.query_instance_offering_by_uuid(self.client, instance_offering_uuid), [])

        # 销毁云路由规格
        vm.delete_instance_offering(self.client, vrouter_instance_offering_uuid)
        self.assertEqual(vm.query_instance_offering_by_uuid(self.client, vrouter_instance_offering_uuid), [])


if __name__ == '__main__':
    unittest.main()
